package frsf.cidisi.exercise.proyectoia.search.actions;

import java.util.ArrayList;
import java.util.Random;

import frsf.cidisi.exercise.proyectoia.clasesProyectoIA.CuadranteBajo;
import frsf.cidisi.exercise.proyectoia.clasesProyectoIA.Esquina;
import frsf.cidisi.exercise.proyectoia.search.*;
import frsf.cidisi.faia.agent.search.SearchAction;
import frsf.cidisi.faia.agent.search.SearchBasedAgentState;
import frsf.cidisi.faia.state.AgentState;
import frsf.cidisi.faia.state.EnvironmentState;

public class IrSur extends SearchAction {

    /**
     * This method updates a tree node state when the search process is running.
     * It does not updates the real world state.
     */
    @Override
    public SearchBasedAgentState execute(SearchBasedAgentState s) {
        StateDrone agente = (StateDrone) s;
        
        int nivel = agente.getNivel();
        
        //Dependiendo el nivel
        switch(nivel){
        	case 1: 
        		//Intencidad de los cuadrantes medios
        		int[] visitadosMedio = agente.getCuadrantesMediosVisitados();
        		//Solo voy al sur si los 2 cuadrantes del norte no tienen intencidad y si es que estoy en el norte
        		if(agente.getCuadranteMedio().getNumero()<3 && (visitadosMedio[2]+visitadosMedio[3])<2)
        		{
        			agente.setCuadranteMedio(agente.getMapa().getCuadranteIndex(agente.getCuadranteMedio().getNumero()+2));
        			agente.incrementarCosto(getCost());
        			agente.setIntensidades(0);
        			return agente;
        		}
        			break;
        	case 2:
        		//Intencidad de los cuadrantes bajos
        		int[] visitadosBajos = agente.getCuadrantesBajosVisitados();
        		//Solo voy al sur si los 2 cuadrantes del norte no tienen intencidad y si es que estoy en el norte
        		if(agente.getCuadranteBajo().getNumero() < 3 && (visitadosBajos[2]+visitadosBajos[3])<2)
        		{
        			agente.setCuadranteBajo(agente.getCuadranteMedio().cuadranteBajoIndex(agente.getCuadranteBajo().getNumero()+2));
        			agente.incrementarCosto(getCost());
        			agente.setIntensidades(0);
        			return agente;
        		}
        			break;
        	case 3:
        		CuadranteBajo cuadrante = agente.getCuadranteBajo();
        		// Variables auxiliares
        		Esquina esquina = agente.getEsquinaActual();
        		Esquina esquinaSur = ((Esquina)cuadrante.verVecinosAdyacentes(esquina)[1]);
        		Esquina esquinaNorte = ((Esquina)cuadrante.verVecinosAdyacentes(esquina)[0]);
        		Esquina esquinaEste = ((Esquina)cuadrante.verVecinosAdyacentes(esquina)[2]);
        		Esquina esquinaOeste = ((Esquina)cuadrante.verVecinosAdyacentes(esquina)[3]);
        		Esquina esquinaDiagonal = ((Esquina)cuadrante.verVecinosAdyacentes(esquina)[4]);

        		boolean bandera=true;
        		int[][] auxiliarV = agente.getEsquinasVisitadas();
        		int auxiliarEsquina = -1;
        		for(int i=0;i<10;i++)
        		{
        			if(auxiliarV[i][0]==esquinaSur.getCoordenada())
        			{
        				auxiliarEsquina=i;
        				if(auxiliarV[i][1]==2)
        					bandera=false;
        			}
        		}
        		
        		if( bandera && (agente.getPersonasPendientesBajos()>0 || agente.getCantidadEsquinas()!=0) && esquinaSur.getCoordenada()!=0)
        		{
	    			agente.incrementarCosto(getCost());
	    			agente.setEsquinaActual(agente.getCuadranteBajo().getEsquinaIndex(esquinaSur.getCoordenada()));
	
					if(auxiliarEsquina==-1)
					{
						int j=0;
						while(auxiliarV[j][0]!=0)
							j++;
						auxiliarV[j][0]=esquinaSur.getCoordenada();
						auxiliarV[j][1]=1;
						auxiliarEsquina=j;
					}
					else
					{
						auxiliarV[auxiliarEsquina][1]=auxiliarV[auxiliarEsquina][1]+1;
					}
					agente.setEsquinasVisitadas(auxiliarV);
					if(auxiliarV[auxiliarEsquina][1]==1)
						agente.setCantidadEsquinas(agente.getCantidadEsquinas()-1);
					
					return agente;
        		}
        		break;
        			
        }
        
        return null;
    }

    /**
     * This method updates the agent state and the real world state.
     */
    @Override
    public EnvironmentState execute(AgentState ast, EnvironmentState est) {
        StateMapa ambiente = (StateMapa) est;
        StateDrone agente = ((StateDrone) ast);
        
        int nivel = ambiente.getNivDrone();
        
        //Dependiendo el nivel
        switch(nivel){
        	case 1: 
        		//Intencidad de los cuadrantes medios
        		int[] intensidadMedio = ambiente.getMapa().intensidadNivelAlto();
        		//Solo voy al sur si los 2 cuadrantes del norte no tienen intencidad y si es que estoy en el norte
        		if(ambiente.getCuadranteMedioDrone().getNumero() < 3)
        		{
        			agente.setCuadranteMedio(agente.getMapa().getCuadranteIndex(agente.getCuadranteMedio().getNumero()+2));
        			agente.incrementarCosto(getCost());
        			//Actualizo el ambiente tambien
        			ambiente.setCuadranteMedioDrone(ambiente.getMapa().getCuadranteIndex(ambiente.getCuadranteMedioDrone().getNumero()+2));
        			agente.setIntensidades(1);
        			return ambiente;
        		}
        			break;
        	case 2:
        		//Intencidad de los cuadrantes bajos
        		CuadranteBajo cuadranteBajo = ambiente.getCuadranteBajoDrone();
        		int[] intensidadBajo = ambiente.getCuadranteMedioDrone().getIntesidadCuadrantesBajos();
        		//Solo voy al sur si los 2 cuadrantes del norte no tienen intencidad y si es que estoy en el norte
        		if(cuadranteBajo.getNumero() < 3)
        		{
        			agente.setCuadranteBajo(agente.getCuadranteMedio().cuadranteBajoIndex(agente.getCuadranteBajo().getNumero()+2));
        			agente.incrementarCosto(getCost());
        			//Actualizo el ambiente tambien
        			ambiente.setCuadranteBajoDrone(ambiente.getCuadranteMedioDrone().cuadranteBajoIndex(cuadranteBajo.getNumero()+2));
        			agente.setIntensidades(1);
        			return ambiente;
        		}
        			break;
        	case 3:
        		CuadranteBajo cuadrante = ambiente.getCuadranteBajoDrone();
        		// Variables auxiliares
        		Esquina esquina = ambiente.getCoordDrone();
        		Esquina esquinaSur = ((Esquina)cuadrante.verVecinosAdyacentes(esquina)[1]);
        		Esquina esquinaNorte = ((Esquina)cuadrante.verVecinosAdyacentes(esquina)[0]);
        		Esquina esquinaEste = ((Esquina)cuadrante.verVecinosAdyacentes(esquina)[2]);
        		Esquina esquinaOeste = ((Esquina)cuadrante.verVecinosAdyacentes(esquina)[3]);
        		Esquina esquinaDiagonal = ((Esquina)cuadrante.verVecinosAdyacentes(esquina)[4]);
        		//boolean esquinaVisitada = agente.getEsquinasVisitadas().contains((Object)esquina);
        		
        		boolean bandera=true;
        		int[][] auxiliarV = agente.getEsquinasVisitadas();
        		int auxiliarEsquina = -1;
        		for(int i=0;i<10;i++)
        		{
        			if(auxiliarV[i][0]==esquinaSur.getCoordenada())
        			{
        				auxiliarEsquina=i;
        				if(auxiliarV[i][1]==2)
        					bandera=false;
        			}
        		}
        		
        		if( bandera && (agente.getPersonasPendientesBajos()>0 || agente.getCantidadEsquinas()!=0))
        		{

	    			agente.incrementarCosto(getCost());
	    			agente.setEsquinaActual(ambiente.getCuadranteBajoDrone().getEsquinaIndex(esquinaSur.getCoordenada()));
	
					if(auxiliarEsquina==-1)
					{
						int j=0;
						while(auxiliarV[j][0]!=0)
							j++;
						auxiliarV[j][0]=esquinaSur.getCoordenada();
						auxiliarV[j][1]=1;
						auxiliarEsquina=j;
					}
					else
					{
						auxiliarV[auxiliarEsquina][1]=auxiliarV[auxiliarEsquina][1]+1;
					}
					agente.setEsquinasVisitadas(auxiliarV);
					if(auxiliarV[auxiliarEsquina][1]==1)
						agente.setCantidadEsquinas(agente.getCantidadEsquinas()-1);
	
	    			//Actualizo el ambiente
	    			ambiente.setCoordDrone(ambiente.getCuadranteBajoDrone().getEsquinaIndex(esquinaSur.getCoordenada()));
	    			agente.setIntensidades(1);
	    			return ambiente;
        		}
  			
        }
        
        return null;
    }

    /**
     * This method returns the action cost.
     */
    @Override
    public Double getCost() {
        return new Double(3);
    }

    /**
     * This method is not important for a search based agent, but is essensial
     * when creating a calculus based one.
     */
    @Override
    public String toString() {
        return "IrSur";
    }
}